package br.pucrs.lognplay.hadoop.test;

import java.util.Calendar;

import org.apache.log4j.Logger;
import org.elasticsearch.action.admin.indices.status.IndicesStatusRequestBuilder;
import org.elasticsearch.action.admin.indices.status.IndicesStatusResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.common.joda.time.DateTime;
import org.elasticsearch.common.joda.time.format.DateTimeFormat;
import org.elasticsearch.index.query.AndFilterBuilder;
import org.elasticsearch.index.query.FilterBuilders;
import org.elasticsearch.index.query.FilteredQueryBuilder;
import org.elasticsearch.index.query.OrFilterBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.facet.datehistogram.DateHistogramFacetBuilder;
import org.elasticsearch.search.facet.terms.TermsFacetBuilder;
import org.elasticsearch.search.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;

import br.pucrs.lognplay.hadoop.ElasticSearchClient;

public class App {

	private static final String DATETIME_FORMAT = "YYYY-MM-dd'T'HH:mm:ss.SSS";

	private static final Logger logger = Logger.getLogger(App.class);

	public static void main(String[] args) {
		App app = new App();

		logger.trace("############# Numero e Volume por indice ##############");
		app.performStatus();

		logger.trace("############# Quantidade de logs por criterio ##############");
		app.performFacetSearch();

		logger.trace("############# Realiza a pesquisa ##############");
		app.performSearch();

	}

	private String formatDate(Calendar date, String pattern) {
		return DateTimeFormat.forPattern(pattern).print(new DateTime(date));
	}

	private void performStatus() {
		ElasticSearchClient esClient = new ElasticSearchClient();
		esClient.startClient();

		IndicesStatusRequestBuilder builder = new IndicesStatusRequestBuilder(esClient.getEsClient().admin().indices());

		IndicesStatusResponse response = builder.execute().actionGet();

		/* Numero de logs por indice */
		logger.trace(response.index("90bea956fe916cf74365c94ad6de87d1").getDocs().numDocs());

		/* Volume de logs por indice (Bytes) */
		logger.trace(response.index("90bea956fe916cf74365c94ad6de87d1").getStoreSize().getBytes());

	}

	private void performSearch() {

		/**
		 * Parametros do usuario
		 */

		Calendar FROM_DATE = Calendar.getInstance();
		Calendar TO_DATE = Calendar.getInstance();

		FROM_DATE.set(Calendar.HOUR, 0);
		FROM_DATE.set(Calendar.MINUTE, 0);
		FROM_DATE.set(Calendar.SECOND, 0);
		FROM_DATE.set(Calendar.MILLISECOND, 0);
		FROM_DATE.add(Calendar.DAY_OF_MONTH, -7);

		String STRING_DO_USUARIO = "log";
		String SEVERITY_TEXT = "info";

		/**
		 * Começa aqui a Query
		 */

		ElasticSearchClient esClient = new ElasticSearchClient();
		SearchRequestBuilder builder = esClient.getEsClient().prepareSearch("90bea956fe916cf74365c94ad6de87d1");

		QueryBuilder queryString;
		if (!STRING_DO_USUARIO.isEmpty()) {
			queryString = QueryBuilders.queryString(STRING_DO_USUARIO);
			((QueryStringQueryBuilder) queryString).field("msg");
			((QueryStringQueryBuilder) queryString).field("hostName");
			((QueryStringQueryBuilder) queryString).field("programName");
			((QueryStringQueryBuilder) queryString).field("syslogFacilityText");
			((QueryStringQueryBuilder) queryString).field("syslogSeverityText");
		} else {
			queryString = QueryBuilders.matchAllQuery();
		}

		// @formatter:off
		
		// severrities e appNames. 
		OrFilterBuilder orFilter = new OrFilterBuilder();
		
		// Fazer um for com os severities e appNames que o cara selecionou
		orFilter.add(FilterBuilders.termFilter("syslogSeverityText", SEVERITY_TEXT));
		orFilter.add(FilterBuilders.termFilter("appName", "58fdaffd8f9135e3c1724e169da6f14d"));
		
		// Date Range
		AndFilterBuilder andFilter = new AndFilterBuilder();
		andFilter.add(
			FilterBuilders.rangeFilter("timeReported")
				.gt(formatDate(FROM_DATE, DATETIME_FORMAT))
				.lt(formatDate(TO_DATE, DATETIME_FORMAT)));

		andFilter.add(orFilter); // nessa parte tem que verificar se o orFilter recebeu pelo menos um criterio ali em cima
		
		FilteredQueryBuilder filteredQuery = new FilteredQueryBuilder(queryString, andFilter);

		// @formatter:on

		builder.setSearchType(SearchType.QUERY_AND_FETCH);
		builder.setQuery(filteredQuery);

		builder.addHighlightedField("msg", 100, 1);
		builder.setHighlighterPreTags("<b>");
		builder.setHighlighterPostTags("</b>");

		/* fields retornados na pesquisa */
		builder.addField("msg");
		builder.addField("timeReported");
		builder.addField("programName");
		builder.addField("hostName");
		builder.addField("syslogSeverityText");
		builder.addField("syslogFacilityText");

		/* ordenacao por score de relevancia */
		builder.addSort(SortBuilders.scoreSort());

		/**
		 * Executa a query
		 * 
		 */

		SearchResponse response = builder.execute().actionGet();
		response.getHits().totalHits();
		if (response.getHits().totalHits() > 0) {
			for (SearchHit hit : response.getHits()) {
				logger.trace("____________________________________________________________");
				logger.trace("Message:      " + hit.field("msg").getValue().toString().trim());
				logger.trace("Severity:     " + hit.field("syslogSeverityText").getValue());
				logger.trace("Facility:     " + hit.field("syslogFacilityText").getValue());
				logger.trace("Program Name: " + hit.field("programName").getValue());
				logger.trace("Host Name:    " + hit.field("hostName").getValue());

				HighlightField highlightedField = hit.highlightFields().get("msg");

				logger.trace("Highlighted Message: " + highlightedField.getFragments()[0]);

			}
		}
		logger.trace(response);
	}

	private void performFacetSearch() {
		ElasticSearchClient esClient = new ElasticSearchClient();
		SearchRequestBuilder builder = esClient.getEsClient().prepareSearch("90bea956fe916cf74365c94ad6de87d1");
		builder.setSearchType(SearchType.COUNT);

		TermsFacetBuilder severityFacet = new TermsFacetBuilder("severity");
		severityFacet.field("syslogSeverityText");

		DateHistogramFacetBuilder logsByYearFacet = new DateHistogramFacetBuilder("logsByYear");
		logsByYearFacet.field("timeReported");
		logsByYearFacet.interval("month");

		DateHistogramFacetBuilder logsByMonthFacet = new DateHistogramFacetBuilder("logsByMonth");
		logsByMonthFacet.field("timeReported");
		logsByMonthFacet.interval("month");

		DateHistogramFacetBuilder logsByDayFacet = new DateHistogramFacetBuilder("logByDay");
		logsByDayFacet.field("timeReported");
		logsByDayFacet.interval("day");

		DateHistogramFacetBuilder logsByHourFacet = new DateHistogramFacetBuilder("logsByHour");
		logsByHourFacet.field("timeReported");
		logsByHourFacet.interval("hour");

		builder.addFacet(severityFacet);
		builder.addFacet(logsByYearFacet);
		builder.addFacet(logsByMonthFacet);
		builder.addFacet(logsByDayFacet);
		builder.addFacet(logsByHourFacet);

		SearchResponse response = builder.execute().actionGet();
		logger.trace(response);
	}

}
